package com.imooc.SmartChargeStation.demo.mqtt.PahoMode.utils;

import com.imooc.SmartChargeStation.demo.mqtt.PahoMode.conf.MqttConf;
import com.imooc.SmartChargeStation.demo.mqtt.PahoMode.service.impl.Callback;
import com.imooc.SmartChargeStation.demo.mqtt.PahoMode.service.impl.MessageListener;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.*;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;

import java.nio.charset.StandardCharsets;

/**
 * author: zpy
 * description: mqtt客户端工具类
 * date: 2025/8/16
 */
@Component
/*
    让Spring在启动的时候自动创建对象，并加入IOC容器中，
    我用的时候，不手动创建实例（用 new 关键字），而是通过@Autowired 自动获取对象
    手动：MessageListener listener = new MessageListener();
    自动：@Autowired MessageListener listener;
*/
@Slf4j
/**
    怎么理解这个？
    MQTT对讲机工具。封装了和 MQTT 服务器打交道的所有 "体力活"，让我们用的时候不用重复写连接、发消息等基础代码，
   直接调用现成的方法就行。

 */
public class MqttClientUtils {

    @Resource
/*
    自动从容器（比如 Spring 的 IOC 容器）中获取需要的对象，并赋值给当前变量，可以直接使用 conf 变量调用 MqttConf 类里的方法（比如 conf.getHost()、conf.getUsername()），
    而不用自己写 MqttConf conf = new MqttConf() 来创建对象了。
 */
    private MqttConf conf;

    @Resource
    private MessageListener listener;

    private MqttClient client;

    private MqttConnectOptions options;

    @PostConstruct
/*
    标记一个方法，让这个方法在当前对象被创建出来，并且所有依赖（比如代码里的 conf、listener）都注入完成后，自动执行。
    只有当所有依赖都准备好（已经注入），才会执行 init() 方法，避免了 “依赖还没准备好就被使用” 的问题。
 */
    public void init(){
        //创建mqtt客户端实例
        createClient();
        //设置连接参数
        getOptions();
        //建立与MQTT服务器的连接
        connect();
        //订阅主题
        subScribe(conf.getTopic());

    }

    /**
     * author: zpy
     * description: 创建mqtt客户端实例
     * @param :
     * @return void
     */
    private void createClient(){

        if(client == null) {
            try {
                //客户端连接哪台MQTT服务器，服务器通过ClientId来唯一标识不同的客户端
                client = new MqttClient(conf.getHost(), conf.getClientId());
                log.info(">>>>>paho模式 MqttClient生成成功<<<<<");
            } catch (MqttException e) {
                log.info(">>>>>paho模式 MqttClient生成失败<<<<<");
                throw new RuntimeException(e);
            }
        }
    }

    /**
     * author: zpy
     * description: 连接
     * @param :
     * @return void
     */
    private void connect(){

        try {
            if(!client.isConnected()) {
                client.connect(options);
                client.setCallback(new Callback());
                log.info(">>>>>paho模式 mqtt连接成功<<<<<");
            }
        } catch (MqttException e) {
            log.error(">>>>>paho模式 mqtt连接失败<<<<<");
            throw new RuntimeException(e);

        }
    };

    /**
     * author: zpy
     * description: 生成mqtt配置对象
     * @param :
     * @return void
     * Understanding:
     */
    private void getOptions() {
        options = new MqttConnectOptions();
        options.setUserName(conf.getUsername());
        //将String类型的密码转为char[]类型
        options.setPassword(conf.getPassword().toCharArray());

    }

    /**
     * author: zpy
     * description: 发送
     * @param topic: 主题
     * @param message: 消息体
     * @return void
     */
    public void publish(String topic, String message){

        MqttMessage mqttMessage = new MqttMessage(message.getBytes(StandardCharsets.UTF_8));

        try {
            client.publish(topic,mqttMessage);
            log.info(">>>>>paho模式 mqtt发送消息成功 <<<<<");
        } catch (MqttException e) {
            log.info(">>>>>paho模式 mqtt发送消息失败 <<<<<");
            throw new RuntimeException(e);
        }
    };

    /**
     * author: zpy
     * description: 订阅
     * @param topic: 主题
     * @return void
     */
    public void subScribe(String topic){

        try {
            client.subscribe(topic,listener);
            log.info(">>>>>paho模式 mqtt订阅主题成功 <<<<<");
        } catch (MqttException e) {
            log.info(">>>>>paho模式 mqtt订阅消息失败 <<<<<");
            throw new RuntimeException(e);
        }
    };

    /**
     * author: zpy
     * description: 断开
     * @param :
     * @return void
     */
    public void disconnct() {

        try {
            client.disconnect();
            log.info(">>>>>paho模式 mqtt断开连接 <<<<<");
        } catch (MqttException e) {
            throw new RuntimeException(e);
        }

    }
}